import { DeviceEventEmitter, NativeModules } from "react-native";
import XLog from "./XLog";
const { MQTTClientLibrary } = NativeModules;

const defaultOptions = {
    userName: "",
    password: "",
    traceEnable: false,
    cleanSession: true,
    connectTimeout: 10,
    keepAliveInterval: 60,
    autoReconnect: true,
    mqttVersion: 0,
    maxReconnectDelay: 128000
}

class MqttClient {
	constructor(options, clientRef, label) {
		this.options = options;
		this.clientRef = clientRef;
		this.clientLabel = label;
		this.eventHandler = {};

		this.dispatchEvent = function(data) {
			if(data && data.clientRef == this.clientRef && data.event) {

				if(this.eventHandler[data.event]) {
					this.eventHandler[data.event](data.message);
				}
			}	
		}
	}

	on(event, callback) {
		this.eventHandler[event] = callback;
	}
	
	connect() {
		return MQTTClientLibrary.connect(this.clientRef);
	}
	
	disconnect() {
		return MQTTClientLibrary.disconnect(this.clientRef);
	}
	
	subscribe(topic, qos) {
		return new Promise((resolve, reject)=>{
			let qos_arr = Array.from({ length: topic.length },item => qos);
			MQTTClientLibrary.subscriberTopics(this.clientRef, topic, qos_arr).then(()=>{
				resolve(true);
			}).catch(error=>{
				XLog.e("subscriber error:", error?.message, topic);
				resolve(false);
			});
		})
	}
	
	unsubscribe(topic) {
		return MQTTClientLibrary.unSubscriberTopics(this.clientRef, topic).catch(error=>{
			console.log("unsubscriber error:",error?.message);
		});
	}
	
	publish(topic, payload, qos, retain) {
		return MQTTClientLibrary.publishMessage(this.clientRef, topic, payload, qos, retain).catch(error=>{
			console.log(`[${this.clientLabel}][${this.clientRef}]publish error:`,error?.message);
		});
	}
	
	isConnected() {
		return MQTTClientLibrary.isConnected(this.clientRef);
	}
}

export default class MQTTClient {
	static clients = [];
	static eventHandler = null;
	static dispatchEvents(data) {
		this.clients.forEach(function(client) {
			client.dispatchEvent(data);
		});
	}

	static setEventHandler() {
		this.eventHandler = DeviceEventEmitter.addListener("mqtt_events", (data) => this.dispatchEvents(data));
	}

	static async createClient(label, options) {
		const optionObj = {
            ...defaultOptions,
            ...options
        };
		let clientRef = await MQTTClientLibrary.createClient(label, optionObj);

		var client = new MqttClient(options, clientRef, label);

		/* Listen mqtt event */
		if(this.eventHandler === null) {
			this.setEventHandler();
		}
		this.clients.push(client);

		return client;
	}

	static removeClient(client) {
		var clientIdx = this.clients.indexOf(client);
		if (clientIdx > -1)	{
			this.clients.splice(clientIdx, 1);
		}
		if (this.clients.length > 0) {
			if (this.eventHandler !== null) {
				this.eventHandler.remove();
				this.setEventHandler();
			}
		}
		return MQTTClientLibrary.removeMqttClient(client.clientRef);
	}

	static getMqttClients(filter) {
		return MQTTClientLibrary.getMqttClients(filter);
	}

	static destroyMqttClientByRef(clientRef) {
		return MQTTClientLibrary.removeMqttClient(clientRef);
	}
}